#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cassert>
#include <cstring>

/*接收&发送缓冲区管理类*/
#define DEFAULT_BUFFER_SIZE 4096
class Buffer {
    private:
        std::vector<char> _buffer;
        size_t _reader_idx;
        size_t _writer_idx;
    private:
        char *begin() { return &*_buffer.begin(); }
        /*返回当前读取位置之前空闲空间大小*/
        size_t prepend_size() { return _reader_idx; }
        /*查看剩余空间是否足够len大小，不够就resize空间大小，够了就将当前读位置的数据移动到空间起始处*/
        void make_space(size_t len) {
            if(writeable_size() + prepend_size() < len) {
                _buffer.resize(_writer_idx + len);
            }else {
                size_t sz = readable_size();
                std::copy(begin() + _reader_idx, begin() + _writer_idx, begin());
                _reader_idx = 0;
                _writer_idx = _reader_idx + readable_size();
            }
        }
        /*将当前写位置向后移动*/
        void has_written(size_t len) {
            assert(len <= writeable_size());
            _writer_idx += len;
        }
        /*确保剩余可写空间大小足够len长度，不够的话就make_space*/
        void ensure_write_able_size(size_t len) {
            if (len > writeable_size()) {
                make_space(len);
            }
            assert(writeable_size() >= len);
        }
        void retrieve_all() {
            _reader_idx = 0;
            _writer_idx = 0;
        }
        /*返回当前写位置地址*/
        char *begin_write() {
            return begin() + _writer_idx;
        }
    public:
        Buffer(size_t init_size = DEFAULT_BUFFER_SIZE):_reader_idx(0), _writer_idx(0), _buffer(init_size) {}
        /*返回当前可读数据大小*/
        size_t readable_size() { return _writer_idx - _reader_idx; }
        /*返回当前可读数据后的可写空间大小*/
        size_t writeable_size() { return _buffer.size() - _writer_idx; }
        /*返回当前读取位置地址*/
        const char *peek() { return begin() + _reader_idx; }
        /*返回当前行的结束地址*/
        const char *find_eol() {
            const void *pos = memchr(peek(), '\n', readable_size());
            return (const char *)pos;
        }
        /*当前读位置向后偏移指定长度*/
        void retrieve(size_t size) {
            assert(size <= readable_size());
            if (size < readable_size()) _reader_idx += size;
            else retrieve_all();
        }
        /*将指定长度的可读数据以string取出，并向后偏移读位置*/
        std::string retrieve_as_string(size_t len) {
            assert(len <= readable_size());
            std::string res(peek(), len);
            retrieve(len);
            return res;
        }
        std::string retrieve_all_as_string() {
            return retrieve_as_string(readable_size());
        }
        std::string getline() {
            const char *pos = find_eol();
            if (pos == NULL) return retrieve_all_as_string();
            /*+1是为了把换行\n字符也取出来*/
            return retrieve_as_string(pos - peek() + 1);
        }
        /*将数据写入缓冲区中*/
        void append(const char *data, size_t len) {
            const char *d = (const char *)data;
            if (len > writeable_size()) {
                ensure_write_able_size(len);
            }
            std::copy(d, d + len, begin_write());
            has_written(len);
        }
};

int main()
{
    std::string body = "Hello World~!!\r\n";
    Buffer buf;
    for (int i = 0; i < 10000; i++) {
        std::string str = std::to_string(i) + " " + body;
        buf.append(str.c_str(), str.size());
    }

    std::ofstream ofs("./test.txt", std::ios::binary | std::ios::trunc);
    ofs << buf.retrieve_all_as_string() << std::endl;
    ofs.close();
    std::cout << buf.retrieve_as_string(11) << std::endl;
    std::cout << "[" << buf.getline() << "]" << std::endl;
    std::cout << "[" << buf.getline() << "]" << std::endl;
    std::cout << "[" << buf.getline() << "]" << std::endl;
    std::cout << "[" << buf.getline() << "]" << std::endl;
    return 0;
}